package com.vvv.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vvv.common.ErrorCode;
import com.vvv.constants.RabbitMQConstant;
import com.vvv.constants.RedisConstant;
import com.vvv.exception.BusinessException;
import com.vvv.mapper.UserCourseinfoMapper;
import com.vvv.model.dto.IdRequest;
import com.vvv.model.dto.UserCourseMessage;
import com.vvv.model.entity.CourseInfo;
import com.vvv.model.entity.User;
import com.vvv.model.entity.UserCourseinfo;
import com.vvv.service.CourseInfoService;
import com.vvv.service.UserCourseinfoService;
import com.vvv.service.UserService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.List;

/**
* @author v
* @description 针对表【user_courseinfo(用户-课)】的数据库操作Service实现
* @createDate 2023-12-08 08:59:20
*/
@Service
public class UserCourseinfoServiceImpl extends ServiceImpl<UserCourseinfoMapper, UserCourseinfo>
    implements UserCourseinfoService {

    @Resource
    private UserService userService;

    @Resource
    private CourseInfoService courseInfoService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RabbitTemplate rabbitTemplate;

    private static final DefaultRedisScript<Long> GRABBING_SCRIPT;

    private static final DefaultRedisScript<Long> DROPPING_SCRIPT;

    static {
        // grabbing
        GRABBING_SCRIPT = new DefaultRedisScript<>();
        // Lua location
        GRABBING_SCRIPT.setLocation(new ClassPathResource("grabbing.lua"));
        // Lua return type
        GRABBING_SCRIPT.setResultType(Long.class);

        // dropping
        DROPPING_SCRIPT = new DefaultRedisScript<>();
        // Lua location
        DROPPING_SCRIPT.setLocation(new ClassPathResource("dropping.lua"));
        // Lua return type
        DROPPING_SCRIPT.setResultType(Long.class);
    }

    @Override
    public boolean grabbingCourse(IdRequest idRequest, HttpServletRequest request) {
        Long courseId = idRequest.getId();
        Long userId = userService.getLoginUser(request).getId();
        if (courseId == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }

        // execute lua
        Long result = stringRedisTemplate.execute(
                GRABBING_SCRIPT,
                Collections.emptyList(), //key
                courseId.toString(), userId.toString() // values
        );
        if (result == 1) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "课已经抢空");
        }
        if (result == 2) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "不可重复抢课");
        }

        // construct message
        UserCourseMessage userCourseMessage = constructMessage(courseId, userId);

        // send to mq
        rabbitTemplate.convertAndSend(
                RabbitMQConstant.COURSE_EXCHANGE_NAME,
                RabbitMQConstant.GRABBING_ROUTING_KEY,
                userCourseMessage
        );
        return true;
    }

    private static UserCourseMessage constructMessage(Long courseId, Long userId) {
        UserCourseMessage userCourseMessage = new UserCourseMessage();
        userCourseMessage.setCourseId(courseId);
        userCourseMessage.setUserId(userId);
        return userCourseMessage;
    }

    @Override
    public boolean droppingCourse(IdRequest idRequest, HttpServletRequest request) {
        Long courseId = idRequest.getId();
        Long userId = userService.getLoginUser(request).getId();
        if (courseId == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
        }
        // execute lua
        Long result = stringRedisTemplate.execute(
                DROPPING_SCRIPT,
                Collections.emptyList(), //key
                courseId.toString(), userId.toString() // values
        );
        if (result == 1) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "不可重复退课");
        }

        // construct message
        UserCourseMessage userCourseMessage = constructMessage(courseId, userId);

        // send to mq , delete userId in async way
        rabbitTemplate.convertAndSend(
                RabbitMQConstant.COURSE_EXCHANGE_NAME,
                RabbitMQConstant.DROPPING_ROUTING_KEY,
                userCourseMessage
        );
        return true;
    }

    @Override
    public CourseInfo querySelectedCourse(HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        List<UserCourseinfo> list = lambdaQuery().eq(UserCourseinfo::getUserId, loginUser.getId()).list();
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        CourseInfo courseInfo = courseInfoService.getById(list.get(0).getCourseId());
        return courseInfo;
    }
}




